/**
 * @overview
 * @using prototype
 * @using Company.Error.ErrorHandler
 * @using Company.Utilities.Utils
 * @using Company.UI.Element
 * @using TemplatesLoader.asp?variables=SlidingCollapserTpl|SlidingCollapserStackTpl&paths=Templates/SlidingCollapserTemplate.txt|Templates/SlidingCollapserStackTemplate.txt
 */


Company.UI.CollapserStacks = {
	stacks: $H()
};


Company.UI.CollapserStacks.createStack = function(collapserType, stackID) {
	var stack;
	
	if (collapserType == "Sliding") {
		stack = new Company.UI.CollapserStack(stackID);
	} else {
		return null;
	}
	
	this.stacks.set(stackID, stack);
	//Event.observe(window, 'resize', function(event) {
	//	Company.UI.CollapserStacks.onResize();
	//	});
	return stack;
}


Company.UI.CollapserStacks.findStack = function(stackID) {
	var stack = this.stacks.get(stackID);
	return stack;
}


Company.UI.CollapserStacks.onResize = function() {
//this.stacks.get("SidebarStack").onResize();
	this.stacks.each(function(pair) {
		pair.value.onResize();
	})
}


/**
 *	@class This object displays and manages a stack of collapsing panels. 
 *	@property {HtmlElement} parent The element that contains the CollapserStack
 *	@property {Array[Company.UI.Collapser]} collapsers Array of collapsers
 */
Company.UI.CollapserStack = function(stackID) {
	this.stackID = stackID;
	this.parent = null;
	this.element = null;
	this.executer = null;
	this.interval = 0.03;
	this.collapsers = $A();
};


Company.UI.CollapserStack.prototype.insertStack = function(parentID) {
	this.parent = $(parentID);
	this.element = $(this.stackID);
	
	if (this.element == null) {
		var myTemplate = new Company.Utilities.Template(this.stackHtml())
		var myValues = {stackID: this.stackID};
		this.parent.innerHTML = myTemplate.evaluate(myValues);
		
		this.element = $(this.stackID);
	}
}


/** 
 * Returns the HTML for the stack container.
 */
Company.UI.CollapserStack.prototype.stackHtml = function() {
	/*
	var str =	'<div ' +
				'id="#{stackID}" ' +
				'class="CollapserStack" ' +
				'style="overflow:hidden;" ' +
				'>\n' +
				'</div>\n';
	
	return str;
	*/
	return SlidingCollapserStackTpl;
}


Company.UI.CollapserStack.prototype.insertNewCollapser = function(collapserID, title, sizing, isOpen) {
	var collapser = new Company.UI.Collapser(collapserID, title, sizing, isOpen);
	collapser.insertCollapser(this.element) 
	this.collapsers[this.collapsers.size()] = collapser;
	return collapser;
} 


Company.UI.CollapserStack.prototype.findCollapser = function(collapserID) {
	var collapser = this.collapsers.find(function(col){
		return col.collapserID == collapserID;
	});
	return collapser;
}


Company.UI.CollapserStack.prototype.toggleCollapser = function(collapserID) {
	var collapserToToggle = this.findCollapser(collapserID);
	var collapser;
	
	if (collapserToToggle.sizing == "variable") {
		//if this is a variable collapser close other variable collapsers and open this one
		for (i = 0; i < this.collapsers.size(); i++) {
			collapser = this.collapsers[i];
			if (collapser.sizing == "variable" && collapser.isOpen) {
				collapser.isOpen = false;
			}
		}
		collapserToToggle.isOpen = true;
	} else {
		//if this is a fixed collapser, toggle it
		collapserToToggle.isOpen = !collapserToToggle.isOpen;

	}
	
	//open the clicked collapser
	this.sizeCollapsers(true);
}


Company.UI.CollapserStack.prototype.sizeCollapsers = function(animate) {

	var collapser;
	var variableCollapser = null;
	var fixedHeight = 0;
	var h;

	//if an executer is running, stop it first
	if (this.executer != null) {
		this.executer.stop();
		this.executer = null;
	}
	
	h = this.parent.getHeight() - parseFloat(this.element.getStyle("marginTop") || 0) - parseFloat(this.element.getStyle("marginBottom") || 0);
	this.element.sizeTo(null, h);

	for (i=0; i<this.collapsers.size(); i++) {
		collapser = this.collapsers[i];
		if (collapser.isOpen) {
			if (collapser.openContent != null) {
				collapser.waitingIcon();
				collapser.openContent(collapser);
			}
		}
		collapser.updateIcon();
		if (collapser.sizing == "fixed" && collapser.isOpen) {
			h = collapser.getOpenHeight();
		} else {
			h = collapser.getClosedHeight();
		}
		
		if (collapser.sizing == "variable" && collapser.isOpen) {
			variableCollapser = collapser;
		} else {
			fixedHeight += h;			
			collapser.desiredHeight = h;
		}
		
	}
	
	if (variableCollapser != null) {
		var remaining = this.element.getHeight() - fixedHeight;
		variableCollapser.setDesiredHeight(remaining);
	}
	
	if (animate) {
		this.executer = new PeriodicalExecuter(function(pe){
			pe.stack.doPeriodicalResize()
		}, this.interval);
		this.executer.stack = this;
		this.executer.byPixels = 4;
		this.executer.accelerating = true;
	} else {
		for (i = 0; i < this.collapsers.size(); i++) {
			collapser = this.collapsers[i];
			collapser.resizeToDesired();
		}
	}
}


Company.UI.CollapserStack.prototype.doPeriodicalResize = function(){
	var remaining;
	var maxRemaining = 0;
	var collapser;
	
	for (i = 0; i < this.collapsers.size(); i++) {
		collapser = this.collapsers[i];
		remaining = collapser.resizeTowardDesired(this.executer.byPixels);
		if (remaining > maxRemaining) {
			maxRemaining = remaining;
		}
	}
	
	if (maxRemaining > 0) {
		if (this.executer.byPixels < 64) {
			this.executer.byPixels = this.executer.byPixels * 2;
		}
	} else {
		this.executer.stop();
		this.executer = null;
	}
}

Company.UI.CollapserStack.prototype.onResize = function(){
	this.sizeCollapsers(false);
}


Company.UI.Collapser = function(collapserID, title, sizing, isOpen) {
	this.collapserID = collapserID;
	this.title = title;
	this.element = null;
	this.sizing = sizing;		//"fixed" | "variable"
	this.isOpen = isOpen;
	this.openContent = null;	//function to call when the collapser is opened (can be used for just-in-time filling)
	this.resizeContent = null;	//function to call after the collapser is resized (to allow contents to adust to size)
};


Company.UI.Collapser.prototype.insertCollapser = function(parentElement) {
	this.element = $(this.collapserID);
	if (this.element == null) {
		var myTemplate = new Company.Utilities.Template(this.collapserHtml())
		var myValues = {	title: this.title,
							collapserID: this.collapserID,
							overflowY: (this.sizing == "fixed") ? "hidden" : "auto",
							display: (this.isOpen) ? "block" : "none",
							openState: (this.isOpen) ? "Open" : "Closed",
							phrase: {openClose: "open/close"}
		};
		
		new Insertion.Bottom(parentElement, myTemplate.evaluate(myValues));
		this.element = $(this.collapserID);
	}
}


Company.UI.Collapser.prototype.setOpenContent = function(openContentFunction) {
	this.openContent = openContentFunction;
}


Company.UI.Collapser.prototype.setResizeContent = function(resizeContentFunction) {
	this.resizeContent = resizeContentFunction;
}


Company.UI.Collapser.prototype.setDesiredHeight = function(desiredHeight) {
	this.desiredHeight = desiredHeight;
	if (this.resizeContent != null) {
		this.resizeContent(desiredHeight, this.getElement("CollapserScroller").getWidth());
	}
}



/** 
 * Returns the HTML for a default collapser.
 */
Company.UI.Collapser.prototype.collapserHtml = function() {
	return SlidingCollapserTpl;
}


Company.UI.Collapser.handleTitleClick = function(element) {
	element = $(element);
	
	var collapserID = element.up("div.CollapserContainer").id;
	var stackID = element.up("div.CollapserStack").id;
	
	Company.UI.CollapserStacks.stacks.get(stackID).toggleCollapser(collapserID);
}


Company.UI.Collapser.prototype.toggleCollapser = function() {
	var frameElement = this.element.down("div.CollapserFrame");
	
	frameElement.toggle();
}


Company.UI.Collapser.prototype.getElement = function(whichElement) {
	return this.element.down("div."+whichElement);
}


Company.UI.Collapser.prototype.setContent = function(element) {
	this.getElement("CollapserContent").appendChild(element);
}


Company.UI.Collapser.prototype.getClosedHeight = function() {
	return this.getElement("CollapserTitle").getHeight();
	//return this.element.getHeight() - this.getElement("CollapserScroller").getHeight();
}


Company.UI.Collapser.prototype.getOpenHeight = function() {
	return this.element.getHeight() - this.getElement("CollapserScroller").getHeight() + this.getElement("CollapserContent").getHeight();
}


Company.UI.Collapser.prototype.resizeHeight = function(height) {
	var desiredScrollerHeight = height - this.getClosedHeight();
	this.getElement("CollapserFrame").sizeTo(null, desiredScrollerHeight);
	this.getElement("CollapserScroller").sizeTo(null, desiredScrollerHeight);
}


Company.UI.Collapser.prototype.resizeToDesired = function() {
	var desiredScrollerHeight = this.desiredHeight - this.getClosedHeight();
	this.getElement("CollapserFrame").sizeTo(null, desiredScrollerHeight);
	this.getElement("CollapserScroller").sizeTo(null, desiredScrollerHeight);
}


Company.UI.Collapser.prototype.resizeTowardDesired = function(byPixels) {
	var scroller = this.getElement("CollapserScroller");
	var scrollerHeight = scroller.getHeight();
	var desiredScrollerHeight = this.desiredHeight - this.getClosedHeight();
	var actualByPixels;
	
	if (desiredScrollerHeight > scrollerHeight) {
		actualByPixels = byPixels;
		if ((scrollerHeight + actualByPixels) > desiredScrollerHeight) {
			//don't go too far
			actualByPixels = desiredScrollerHeight - scrollerHeight;
		}
	} else if (desiredScrollerHeight < scrollerHeight) {
		actualByPixels = byPixels * -1;
		if ((scrollerHeight + actualByPixels) < desiredScrollerHeight) {
			//don't go too far
			actualByPixels =  desiredScrollerHeight - scrollerHeight;
		}
	} else {
		actualByPixels = 0;
	}
	
	if (actualByPixels != 0) {
		this.getElement("CollapserFrame").sizeTo(null, scrollerHeight + actualByPixels);
		scroller.sizeTo(null, scrollerHeight + actualByPixels);
	}
	
	return Math.abs(desiredScrollerHeight - scroller.getHeight());
}

Company.UI.Collapser.prototype.updateIcon = function() {
	var iconElement = this.getElement("CollapserIcon");
	iconElement.removeClassName("CollapserIconClosed");
	iconElement.removeClassName("CollapserIconOpen");
	iconElement.removeClassName("CollapserIconWaiting");
	
	if (this.isOpen) {
		iconElement.addClassName("CollapserIconOpen");
	} else {
		iconElement.addClassName("CollapserIconClosed");
	}
}

Company.UI.Collapser.prototype.waitingIcon = function() {
	var iconElement = this.getElement("CollapserIcon");
	iconElement.removeClassName("CollapserIconClosed");
	iconElement.removeClassName("CollapserIconOpen");
	iconElement.removeClassName("CollapserIconWaiting");
	
	iconElement.addClassName("CollapserIconWaiting");
}
